package com.pig4cloud.pigx.user.schedule;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.pig4cloud.pigx.common.customize.redis.utils.RedisUtils;
import com.pig4cloud.pigx.user.constant.RedisKeyPrefixConstant;
import com.pig4cloud.pigx.user.constant.RedisMessageType;
import com.pig4cloud.pigx.user.constant.WalletConstant;
import com.pig4cloud.pigx.user.dto.TronWithdrawal;
import com.pig4cloud.pigx.user.entity.Currency;
import com.pig4cloud.pigx.user.entity.User;
import com.pig4cloud.pigx.user.entity.WithdrawalRecord;
import com.pig4cloud.pigx.user.enums.UserEnums;
import com.pig4cloud.pigx.user.enums.WalletStatusEnums;
import com.pig4cloud.pigx.user.service.CurrencyService;
import com.pig4cloud.pigx.user.service.EmailService;
import com.pig4cloud.pigx.user.service.UserService;
import com.pig4cloud.pigx.user.service.WithdrawalRecordService;
import lombok.AllArgsConstructor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.redisson.api.RLock;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.Request;
import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;

import java.io.IOException;
import java.math.RoundingMode;
import java.util.*;

/**
 * 充值记录校验
 *
 */
@Component
@EnableScheduling
@AllArgsConstructor
public class WithdrawalRecordCheckTask {

	private final RedisTemplate redis;

	private final RedisUtils redisUtils;

	private final EmailService emailService;

	private final WithdrawalRecordService withdrawalRecordService;

	private final UserService userService;

	private final CurrencyService currencyService;

	private final OkHttpClient okHttpClient;

	@Scheduled(fixedDelay = 500)
	public void withdrawalCheckTask() {
		// 分布式锁
		RLock lock = redisUtils.getLock(RedisKeyPrefixConstant.WITHDRAWAL_RECORD_CHECK_LOCK, null);
		if (Objects.isNull(lock)) {
			return;
		}
		try {
			Set<String> keys = redis.opsForHash().keys(RedisKeyPrefixConstant.WITHDRAWAL_RECORD_CHECK);
			for (String key : keys) {
				try {
					Integer id = (Integer) redis.opsForHash().get(RedisKeyPrefixConstant.WITHDRAWAL_RECORD_CHECK, key);
					if (id == null) {
						break;
					}
					// 查询提现记录
					WithdrawalRecord record = withdrawalRecordService.getById(Long.valueOf(key));
					if (record == null ){
						continue;
					}
					if (record.getCurrency().equals(WalletConstant.USDT)) {
						if (record.getPublicChain().equals(UserEnums.Chain.BSC.getValue())) {
							Currency currency = currencyService.getCurrency(WalletConstant.USDT, UserEnums.Chain.BSC.getValue());
							Web3j web3j = Web3j.build(new HttpService(currency.getNodeAddress()));
							Request<?, EthGetTransactionReceipt> ethGetTransactionReceiptRequest = web3j.ethGetTransactionReceipt(record.getTransactionHash());
							EthGetTransactionReceipt send = ethGetTransactionReceiptRequest.send();
							Optional<TransactionReceipt> transactionReceipt = send.getTransactionReceipt();
							if (transactionReceipt.isPresent()) {
								record.setState(WalletStatusEnums.Status.SUCCESS.getValue());
							} else {
								record.setState(WalletStatusEnums.Status.FAIL.getValue());
							}
						}
						if (record.getPublicChain().equals(UserEnums.Chain.TRON.getValue())) {
							Currency currency = currencyService.getCurrency(WalletConstant.USDT, UserEnums.Chain.TRON.getValue());
							MediaType mediaType = MediaType.parse("application/json");
							RequestBody body = RequestBody.create(mediaType, "{\"value\":\"" + record.getTransactionHash() + "\"}");

							okhttp3.Request request = new okhttp3.Request.Builder()
									.url(currency.getNodeAddress() + "walletsolidity/gettransactionbyid")
									.post(body)
									.addHeader("Accept", "application/json")
									.addHeader("Content-Type", "application/json")
									.build();
							Response response = null;
							try {
								response = okHttpClient.newCall(request).execute();
							} catch (IOException e) {
								throw new RuntimeException(e);
							}
							String res = null;
							try {
								res = response.body().string();
							} catch (IOException e) {
								throw new RuntimeException(e);
							}
							TronWithdrawal tronWithdrawal = JSONUtil.toBean(res, TronWithdrawal.class);

							if (!CollUtil.isNotEmpty(tronWithdrawal.getRet())) {
								continue;
							}
							if ("SUCCESS".equals(tronWithdrawal.getRet().get(0).getContractRet())) {
								record.setState(WalletStatusEnums.Status.SUCCESS.getValue());
							} else {
								record.setState(WalletStatusEnums.Status.FAIL.getValue());
							}
						}
						withdrawalRecordService.updateById(record);
						// 获取用户
						User user = userService.getById(record.getUserId());
						if (user == null) {
							continue;
						}
						// 拼接邮件参数
						Map<String, String> map = new HashMap<>(3);
						map.put("${actualWithdrawalAmount}",
								record.getActualWithdrawalAmount().setScale(6, RoundingMode.DOWN).stripTrailingZeros().toPlainString());
						map.put("${arrivalAddress}",record.getArrivalAddress());
						map.put("${transactionHash}",record.getTransactionHash());
						// 发送邮件
						emailService.sendEmail(user, RedisMessageType.Withdrawal_Success,map);
					}
					redis.opsForHash().delete(RedisKeyPrefixConstant.WITHDRAWAL_RECORD_CHECK, key);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			redisUtils.releaseLock(lock);
		}
	}

}
